
package l1j.server.server.model.Instance;

//
import static l1j.server.server.model.item.L1ItemId.B_POTION_OF_GREATER_HASTE_SELF;
import static l1j.server.server.model.item.L1ItemId.B_POTION_OF_HASTE_SELF;
import static l1j.server.server.model.item.L1ItemId.POTION_OF_EXTRA_HEALING;
import static l1j.server.server.model.item.L1ItemId.POTION_OF_GREATER_HASTE_SELF;
import static l1j.server.server.model.item.L1ItemId.POTION_OF_GREATER_HEALING;
import static l1j.server.server.model.item.L1ItemId.POTION_OF_HASTE_SELF;
import static l1j.server.server.model.item.L1ItemId.POTION_OF_HEALING;
import static l1j.server.server.model.skill.L1SkillId.CANCELLATION;
import static l1j.server.server.model.skill.L1SkillId.COUNTER_BARRIER;
import static l1j.server.server.model.skill.L1SkillId.POLLUTE_WATER;
import static l1j.server.server.model.skill.L1SkillId.STATUS_HASTE;
import static l1j.server.server.model.skill.L1SkillId.WIND_SHACKLE;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.logging.Level;
import java.util.logging.Logger;

import l1j.opqlo.NewSystem.Attack.L1AttackModel;
import l1j.opqlo.NewSystem.Attack.L1AttackNpc;
import l1j.opqlo.Server.L1World.L1World;
import l1j.server.Config;
import l1j.server.Thread.GeneralThreadPool;
import l1j.server.server.ActionCodes;
import l1j.server.server.datatables.NpcChatTable;
import l1j.server.server.datatables.NpcTable;
import l1j.server.server.datatables.SprTable;
import l1j.server.server.model.L1Character;
import l1j.server.server.model.L1GroundInventory;
import l1j.server.server.model.L1HateList;
import l1j.server.server.model.L1Inventory;
import l1j.server.server.model.L1Magic;
import l1j.server.server.model.L1MobGroupInfo;
import l1j.server.server.model.L1MobSkillUse;
import l1j.server.server.model.L1NpcChatTimer;
import l1j.server.server.model.L1Object;
import l1j.server.server.model.L1Spawn;
import l1j.server.server.model.skill.L1SkillUse;
import l1j.server.server.serverpackets.S_ChangeShape;
import l1j.server.server.serverpackets.S_DoActionGFX;
import l1j.server.server.serverpackets.S_NPCPack;
import l1j.server.server.serverpackets.S_RemoveObject;
import l1j.server.server.serverpackets.S_SkillHaste;
import l1j.server.server.serverpackets.S_SkillSound;
import l1j.server.server.templates.L1Npc;
import l1j.server.server.templates.L1NpcChat;
import l1j.server.server.utils.Random;
import l1j.william.MobTalk;//TODO 怪物說話 use 阿傑 code 1/3
import l1j.server.server.serverpackets.S_NPCTalkReturn;//TODO 家畜對話阿傑 code 1/2

public class L1NpcInstance extends L1Character {
	class DigestItemTimer implements Runnable {
		// @Override
		@Override
		public void run() {
			L1NpcInstance.this._digestItemRunning = true;
			while (!L1NpcInstance.this._destroyed && L1NpcInstance.this._digestItems.size() > 0) {
				try {
					Thread.sleep(1000);
				} catch (final Exception exception) {
					break;
				}

				final Object[] keys = L1NpcInstance.this._digestItems.keySet().toArray();
				for (final Object key2 : keys) {
					final Integer key = (Integer) key2;
					final Integer digestCounter = L1NpcInstance.this._digestItems.get(key) -1;
					//digestCounter -= 1;
					if (digestCounter <= 0) {
						L1NpcInstance.this._digestItems.remove(key);
						final L1ItemInstance digestItem = L1NpcInstance.this.getInventory().getItem(key);
						if (digestItem != null) {
							L1NpcInstance.this.getInventory().removeItem(digestItem,
									digestItem.getCount());
						}
					} else {
						L1NpcInstance.this._digestItems.put(key, digestCounter);
					}
				}
			}
			L1NpcInstance.this._digestItemRunning = false;
		}
	}

	class HprTimer extends TimerTask {
		private final int _point;

		public HprTimer(int point) {
			if (point < 1) {
				point = 1;
			}
			this._point = point;
		}

		@Override
		public void run() {
			try {
				if (!L1NpcInstance.this._destroyed && !L1NpcInstance.this.isDead()
						&& L1NpcInstance.this.getCurrentHp() > 0 && L1NpcInstance.this.getCurrentHp() < L1NpcInstance.this.getMaxHp()) {
					L1NpcInstance.this.setCurrentHp(L1NpcInstance.this.getCurrentHp() + this._point);
				} else {
					this.cancel();
					L1NpcInstance.this._hprRunning = false;
				}
			} catch (final Exception e) {
				_log.log(Level.SEVERE, e.getLocalizedMessage(), e);
			}
		}
	}
	class MprTimer extends TimerTask {
		private final int _point;

		public MprTimer(int point) {
			if (point < 1) {
				point = 1;
			}
			this._point = point;
		}

		@Override
		public void run() {
			try {
				if (!L1NpcInstance.this._destroyed && !L1NpcInstance.this.isDead()
						&& L1NpcInstance.this.getCurrentHp() > 0 && L1NpcInstance.this.getCurrentMp() < L1NpcInstance.this.getMaxMp()) {
					L1NpcInstance.this.setCurrentMp(L1NpcInstance.this.getCurrentMp() + this._point);
				} else {
					this.cancel();
					L1NpcInstance.this._mprRunning = false;
				}
			} catch (final Exception e) {
				_log.log(Level.SEVERE, e.getLocalizedMessage(), e);
			}
		}
	}
	//	interface NpcAI {
	//		public void start();
	//	}

	//	class NpcAIThreadImpl implements Runnable, NpcAI {
	//		// @Override
	//		@Override
	//		public void run() {
	//			try {
	//				L1NpcInstance.this.setAiRunning(true);
	//				while (!L1NpcInstance.this._destroyed && !L1NpcInstance.this.isDead() && L1NpcInstance.this.getCurrentHp() > 0
	//						&& L1NpcInstance.this.getHiddenStatus() == HIDDEN_STATUS_NONE) {
	//					/*
	//					 * if (_paralysisTime > 0) { try {
	//					 * Thread.sleep(_paralysisTime); } catch (Exception
	//					 * exception) { break; } finally { setParalyzed(false);
	//					 * _paralysisTime = 0; } }
	//					 */
	//					while (L1NpcInstance.this.isParalyzed() || L1NpcInstance.this.isSleeped()) {
	//						try {
	//							Thread.sleep(200);
	//						} catch (final InterruptedException e) {
	//							L1NpcInstance.this.setParalyzed(false);
	//						}
	//					}
	//
	//					if (L1NpcInstance.this.AIProcess()) {
	//						break;
	//					}
	//					try {
	//						// 指定時間分スレッド停止
	//						Thread.sleep(L1NpcInstance.this.getSleepTime());
	//					} catch (final Exception e) {
	//						break;
	//					}
	//				}
	//				L1NpcInstance.this._mobSkill.resetAllSkillUseCount();
	//				do {
	//					try {
	//						Thread.sleep(L1NpcInstance.this.getSleepTime());
	//					} catch (final Exception e) {
	//						break;
	//					}
	//				} while (L1NpcInstance.this.isDeathProcessing());
	//				L1NpcInstance.this.allTargetClear();
	//				L1NpcInstance.this.setAiRunning(false);
	//			} catch (final Exception e) {
	//				_log.log(Level.WARNING, "Npc物件編號"+L1NpcInstance.this.getId()+" 名稱:"+L1NpcInstance.this.getName()+"AI發生例外的錯誤。", e);
	//			}
	//		}
	//
	//		@Override
	//		public void start() {
	//			GeneralThreadPool.getInstance().execute(NpcAIThreadImpl.this);
	//		}
	//	}
	//	class NpcAITimerImpl extends TimerTask implements NpcAI {
	//		/**
	//		 * 死亡処理の終了を待つタイマー
	//		 */
	//		private class DeathSyncTimer extends TimerTask {
	//			@Override
	//			public void run() {
	//				if (L1NpcInstance.this.isDeathProcessing()) {
	//					this.schedule(L1NpcInstance.this.getSleepTime());
	//					return;
	//				}
	//				L1NpcInstance.this.allTargetClear();
	//				L1NpcInstance.this.setAiRunning(false);
	//			}
	//
	//			private void schedule(int delay) {
	//				_timerPool.getTimer().schedule(new DeathSyncTimer(), delay);
	//			}
	//		}
	//
	//		private boolean notContinued() {
	//			return L1NpcInstance.this._destroyed || L1NpcInstance.this.isDead() || L1NpcInstance.this.getCurrentHp() <= 0
	//					|| L1NpcInstance.this.getHiddenStatus() != HIDDEN_STATUS_NONE;
	//		}
	//
	//		@Override
	//		public void run() {
	//			try {
	//				if (this.notContinued()) {
	//					this.stop();
	//					return;
	//				}
	//
	//				// XXX 同期がとても怪しげな麻痺判定
	//				if (0 < L1NpcInstance.this._paralysisTime) {
	//					this.schedule(L1NpcInstance.this._paralysisTime);
	//					L1NpcInstance.this._paralysisTime = 0;
	//					L1NpcInstance.this.setParalyzed(false);
	//					return;
	//				} else if (L1NpcInstance.this.isParalyzed() || L1NpcInstance.this.isSleeped()) {
	//					this.schedule(200);
	//					return;
	//				}
	//
	//				if (!L1NpcInstance.this.AIProcess()) { // AIを続けるべきであれば、次の実行をスケジュールし、終了
	//					this.schedule(L1NpcInstance.this.getSleepTime());
	//					return;
	//				}
	//				this.stop();
	//			} catch (final Exception e) {
	//				_log.log(Level.WARNING, "Npc物件編號"+L1NpcInstance.this.getId()+" 名稱:"+L1NpcInstance.this.getName()+"AI發生例外的錯誤。", e);
	//			}
	//		}
	//
	//		// 同じインスタンスをTimerへ登録できない為、苦肉の策。
	//		private void schedule(int delay) {
	//			_timerPool.getTimer().schedule(new NpcAITimerImpl(), delay);
	//		}
	//
	//		@Override
	//		public void start() {
	//			L1NpcInstance.this.setAiRunning(true);
	//			_timerPool.getTimer().schedule(NpcAITimerImpl.this, 0);
	//		}
	//
	//		private void stop() {
	//			L1NpcInstance.this._mobSkill.resetAllSkillUseCount();
	//			_timerPool.getTimer().schedule(new DeathSyncTimer(), 0); // 死亡同期を開始
	//		}
	//	}
	private static final long serialVersionUID = 1L;
	public static final int MOVE_SPEED = 0;
	public static final int ATTACK_SPEED = 1;

	public static final int MAGIC_SPEED = 2;
	public static final int HIDDEN_STATUS_NONE = 0;
	public static final int HIDDEN_STATUS_SINK = 1;
	public static final int HIDDEN_STATUS_FLY = 2;

	public static final int HIDDEN_STATUS_ICE = 3;
	public static final int SUCCBUS_TELEPORT_DELAY = 4;//TODO 思克巴瀕死傳送延遲by9001183ex

	public static final int CHAT_TIMING_APPEARANCE = 0;
	public static final int CHAT_TIMING_DEAD = 1;

	public static final int CHAT_TIMING_HIDE = 2;
	public static final int CHAT_TIMING_GAME_TIME = 3;
	private static Logger _log = Logger.getLogger(L1NpcInstance.class.getName());


	private L1Npc _npcTemplate;

	private L1Spawn _spawn;

	private int _spawnNumber; // L1Spawnで管理されているナンバー

	private int _petcost; // ペットになったときのコスト

	public L1Inventory _inventory = new L1Inventory();

	private L1MobSkillUse _mobSkill;

	// 作用距離
	public static final int DISTANCE = 20;

	// ■■■■■■■■■■■■■ ＡＩ関連 ■■■■■■■■■■■

	// 対象を初めて発見したとき。（テレポート用）
	private boolean firstFound = true;

	// 経路探索範囲（半径） ※上げすぎ注意！！
	public static int courceRange = 15;

	/**
	 * マルチ(コア)プロセッサをサポートする為のタイマープール。 AIの実装タイプがタイマーの場合に使用される。
	 */
	//	private static final TimerPool _timerPool = new TimerPool(4);

	public static void shuffle(final L1Object[] arr) {
		for (int i = arr.length - 1; i > 0; i--) {
			final int t = (int) (Math.random() * i);

			// 選ばれた値と交換する
			final L1Object tmp = arr[i];
			arr[i] = arr[t];
			arr[t] = tmp;
		}
	}

	// 吸われたMP
	private int _drainedMana = 0;

	// 休憩
	private boolean _rest = false;

	// ランダム移動時の距離と方向
	private int _randomMoveDistance = 0;

	private int _randomMoveDirection = 0;

	private boolean _aiRunning = false; // ＡＩが実行中か

	// ※ＡＩをスタートさせる時にすでに実行されてないか確認する時に使用
	private boolean _actived = false; // ＮＰＣがアクティブか

	// ※この値がfalseで_targetがいる場合、アクティブになって初行動とみなしヘイストポーション等を使わせる判定で使用
	private boolean _firstAttack = false; // ファーストアッタクされたか

	private int _sleep_time; // ＡＩを停止する時間(ms) ※行動を起こした場合に所要する時間をセット

	protected L1HateList _hateList = new L1HateList();

	protected L1HateList _dropHateList = new L1HateList();

	// ※攻撃するターゲットの判定とＰＴ時のドロップ判定で使用
	protected List<L1ItemInstance> _targetItemList = new ArrayList<L1ItemInstance>(); // ダーゲットアイテム一覧

	protected L1Character _target = null; // 現在のターゲット

	protected L1ItemInstance _targetItem = null; // 現在のターゲットアイテム

	protected L1Character _master = null; // 主人orグループリーダー

	// EXP、Drop分配中はターゲットリスト、ヘイトリストをクリアしない

	private int _paralysisTime = 0; // Paralysis RestTime

	// アイテム消化
	private HashMap<Integer, Integer> _digestItems;

	public boolean _digestItemRunning = false;

	private int _passispeed;

	private int _atkspeed;

	private boolean _pickupItem;

	// アイテムの使用判定及び使用
	public static final int USEITEM_HEAL = 0;
	public static final int USEITEM_HASTE = 1;
	public static int[] healPotions = { POTION_OF_GREATER_HEALING,
		POTION_OF_EXTRA_HEALING, POTION_OF_HEALING };
	public static int[] haestPotions = { B_POTION_OF_GREATER_HASTE_SELF,
		POTION_OF_GREATER_HASTE_SELF, B_POTION_OF_HASTE_SELF,
		POTION_OF_HASTE_SELF };
	/**
	 * 對於前進方向是否有障礙的確認
	 * @param h
	 * @return
	 */
	//	public static int checkObject(final int x,final  int y,final  short m,final  int d) { // 起点Ｘ 起点Ｙ
	//		// マップＩＤ
	//		// 進行方向
	//		final L1Map map = L1WorldMap.getInstance().getMap(m);
	//
	//		if (d == 1) {
	//			if (map.isPassable(x, y, 1)) {
	//				return 1;
	//			} else if (map.isPassable(x, y, 0)) {
	//				return 0;
	//			} else if (map.isPassable(x, y, 2)) {
	//				return 2;
	//			}
	//		} else if (d == 2) {
	//			if (map.isPassable(x, y, 2)) {
	//				return 2;
	//			} else if (map.isPassable(x, y, 1)) {
	//				return 1;
	//			} else if (map.isPassable(x, y, 3)) {
	//				return 3;
	//			}
	//		} else if (d == 3) {
	//			if (map.isPassable(x, y, 3)) {
	//				return 3;
	//			} else if (map.isPassable(x, y, 2)) {
	//				return 2;
	//			} else if (map.isPassable(x, y, 4)) {
	//				return 4;
	//			}
	//		} else if (d == 4) {
	//			if (map.isPassable(x, y, 4)) {
	//				return 4;
	//			} else if (map.isPassable(x, y, 3)) {
	//				return 3;
	//			} else if (map.isPassable(x, y, 5)) {
	//				return 5;
	//			}
	//		} else if (d == 5) {
	//			if (map.isPassable(x, y, 5)) {
	//				return 5;
	//			} else if (map.isPassable(x, y, 4)) {
	//				return 4;
	//			} else if (map.isPassable(x, y, 6)) {
	//				return 6;
	//			}
	//		} else if (d == 6) {
	//			if (map.isPassable(x, y, 6)) {
	//				return 6;
	//			} else if (map.isPassable(x, y, 5)) {
	//				return 5;
	//			} else if (map.isPassable(x, y, 7)) {
	//				return 7;
	//			}
	//		} else if (d == 7) {
	//			if (map.isPassable(x, y, 7)) {
	//				return 7;
	//			} else if (map.isPassable(x, y, 6)) {
	//				return 6;
	//			} else if (map.isPassable(x, y, 0)) {
	//				return 0;
	//			}
	//		} else if (d == 0) {
	//			if (map.isPassable(x, y, 0)) {
	//				return 0;
	//			} else if (map.isPassable(x, y, 7)) {
	//				return 7;
	//			} else if (map.isPassable(x, y, 1)) {
	//				return 1;
	//			}
	//		}
	//		return -1;
	//	}
	// ----------From L1Character-------------
	private String _nameId; // ● ネームＩＤ
	private boolean _Agro; // ● アクティブか
	private boolean _Agrocoi; // ● インビジアクティブか
	private boolean _Agrososc; // ● 変身アクティブか
	private int _homeX; // ● ホームポイントＸ（モンスターの戻る位置とかペットの警戒位置）
	private int _homeY; // ● ホームポイントＹ（モンスターの戻る位置とかペットの警戒位置）

	private boolean _reSpawn; // ● 再ポップするかどうか

	private int _lightSize; // ● ライト ０．なし １～１４．大きさ

	private boolean _weaponBreaked; // ● ウェポンブレイク中かどうか

	private int _hiddenStatus; // ● 地中に潜ったり、空を飛んでいる状態

	// 行動距離
	private int _movementDistance = 0;

	// 表示用ロウフル
	private int _tempLawful = 0;

	public boolean _destroyed = false; // このインスタンスが破棄されているか

	private int _deadTimerTemp = -1;// 死亡時間
	private boolean _isResurrect;// 是復活過的

	private L1MobGroupInfo _mobGroupInfo = null;

	private int _mobGroupId = 0;

	//TODO 守護神給道具順序by seroidv
	private boolean _isDropitems = false;

	private boolean _forDropitems = false;

	public boolean isQuestMob = false; //opqlo 是否為任務怪
	public int ADENA =0;
	protected NpcMoveExecutor _npcMove = null;// XXX

	public L1NpcInstance(final L1Npc template) {
		this.setStatus(0);
		this.setMoveSpeed(0);
		this.setDead(false);
		this.setStatus(0);
		this.setreSpawn(false);
		this._npcMove = new NpcMove(this);
		if (template != null) {
			this.setting_template(template);
		}
	}
	//	private void _getFront(final int[] ary, final int d) {
	//		if (d == 1) {
	//			ary[4] = 2;
	//			ary[3] = 0;
	//			ary[2] = 1;
	//			ary[1] = 3;
	//			ary[0] = 7;
	//		} else if (d == 2) {
	//			ary[4] = 2;
	//			ary[3] = 4;
	//			ary[2] = 0;
	//			ary[1] = 1;
	//			ary[0] = 3;
	//		} else if (d == 3) {
	//			ary[4] = 2;
	//			ary[3] = 4;
	//			ary[2] = 1;
	//			ary[1] = 3;
	//			ary[0] = 5;
	//		} else if (d == 4) {
	//			ary[4] = 2;
	//			ary[3] = 4;
	//			ary[2] = 6;
	//			ary[1] = 3;
	//			ary[0] = 5;
	//		} else if (d == 5) {
	//			ary[4] = 4;
	//			ary[3] = 6;
	//			ary[2] = 3;
	//			ary[1] = 5;
	//			ary[0] = 7;
	//		} else if (d == 6) {
	//			ary[4] = 4;
	//			ary[3] = 6;
	//			ary[2] = 0;
	//			ary[1] = 5;
	//			ary[0] = 7;
	//		} else if (d == 7) {
	//			ary[4] = 6;
	//			ary[3] = 0;
	//			ary[2] = 1;
	//			ary[1] = 5;
	//			ary[0] = 7;
	//		} else if (d == 0) {
	//			ary[4] = 2;
	//			ary[3] = 6;
	//			ary[2] = 0;
	//			ary[1] = 1;
	//			ary[0] = 7;
	//		}
	//	}

	//	private void _moveLocation(final int[] ary,final int d) {
	//		if (d == 1) {
	//			ary[0] = ary[0] + 1;
	//			ary[1] = ary[1] - 1;
	//		} else if (d == 2) {
	//			ary[0] = ary[0] + 1;
	//		} else if (d == 3) {
	//			ary[0] = ary[0] + 1;
	//			ary[1] = ary[1] + 1;
	//		} else if (d == 4) {
	//			ary[1] = ary[1] + 1;
	//		} else if (d == 5) {
	//			ary[0] = ary[0] - 1;
	//			ary[1] = ary[1] + 1;
	//		} else if (d == 6) {
	//			ary[0] = ary[0] - 1;
	//		} else if (d == 7) {
	//			ary[0] = ary[0] - 1;
	//			ary[1] = ary[1] - 1;
	//		} else if (d == 0) {
	//			ary[1] = ary[1] - 1;
	//		}
	//		ary[2] = d;
	//	}
	//
	//	// ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■

	//	// 目標までの最短経路の方向を返す
	//	// ※目標を中心とした探索範囲のマップで探索
	//	private int _serchCource(final int x,final  int y) // 目標点Ｘ 目標点Ｙ
	//	{
	//		int i;
	//		final int locCenter = courceRange + 1;
	//		final int diff_x = x - locCenter; // Ｘの実際のロケーションとの差
	//		final int diff_y = y - locCenter; // Ｙの実際のロケーションとの差
	//		int[] locBace = { this.getX() - diff_x, this.getY() - diff_y, 0, 0 }; // Ｘ Ｙ
	//		// 方向
	//		// 初期方向
	//		final int[] locNext = new int[4];
	//		int[] locCopy;
	//		final int[] dirFront = new int[5];
	//		final boolean serchMap[][] = new boolean[locCenter * 2 + 1][locCenter * 2 + 1];
	//		final LinkedList<int[]> queueSerch = new LinkedList<int[]>();
	//
	//		// 探索用マップの設定
	//		for (int j = courceRange * 2 + 1; j > 0; j--) {
	//			for (i = courceRange - Math.abs(locCenter - j); i >= 0; i--) {
	//				serchMap[j][locCenter + i] = true;
	//				serchMap[j][locCenter - i] = true;
	//			}
	//		}
	//
	//		// 初期方向の設置
	//		final int[] firstCource = { 2, 4, 6, 0, 1, 3, 5, 7 };
	//		for (i = 0; i < 8; i++) {
	//			System.arraycopy(locBace, 0, locNext, 0, 4);
	//			this._moveLocation(locNext, firstCource[i]);
	//			if (locNext[0] - locCenter == 0 && locNext[1] - locCenter == 0) {
	//				// 最短経路が見つかった場合:隣
	//				return firstCource[i];
	//			}
	//			if (serchMap[locNext[0]][locNext[1]]) {
	//				final int tmpX = locNext[0] + diff_x;
	//				final int tmpY = locNext[1] + diff_y;
	//				boolean found = false;
	//				if (i == 0) {
	//					found = this.getMap().isPassable(tmpX, tmpY + 1, i);
	//				} else if (i == 1) {
	//					found = this.getMap().isPassable(tmpX - 1, tmpY + 1, i);
	//				} else if (i == 2) {
	//					found = this.getMap().isPassable(tmpX - 1, tmpY, i);
	//				} else if (i == 3) {
	//					found = this.getMap().isPassable(tmpX - 1, tmpY - 1, i);
	//				} else if (i == 4) {
	//					found = this.getMap().isPassable(tmpX, tmpY - 1, i);
	//				} else if (i == 5) {
	//					found = this.getMap().isPassable(tmpX + 1, tmpY - 1, i);
	//				} else if (i == 6) {
	//					found = this.getMap().isPassable(tmpX + 1, tmpY, i);
	//				} else if (i == 7) {
	//					found = this.getMap().isPassable(tmpX + 1, tmpY + 1, i);
	//				}
	//				if (found)// 移動経路があった場合
	//				{
	//					locCopy = new int[4];
	//					System.arraycopy(locNext, 0, locCopy, 0, 4);
	//					locCopy[2] = firstCource[i];
	//					locCopy[3] = firstCource[i];
	//					queueSerch.add(locCopy);
	//				}
	//				serchMap[locNext[0]][locNext[1]] = false;
	//			}
	//		}
	//		locBace = null;
	//
	//		// 最短経路を探索
	//		while (queueSerch.size() > 0) {
	//			locBace = queueSerch.removeFirst();
	//			this._getFront(dirFront, locBace[2]);
	//			for (i = 4; i >= 0; i--) {
	//				System.arraycopy(locBace, 0, locNext, 0, 4);
	//				this._moveLocation(locNext, dirFront[i]);
	//				if (locNext[0] - locCenter == 0 && locNext[1] - locCenter == 0) {
	//					return locNext[3];
	//				}
	//				if (serchMap[locNext[0]][locNext[1]]) {
	//					final int tmpX = locNext[0] + diff_x;
	//					final int tmpY = locNext[1] + diff_y;
	//					boolean found = false;
	//					if (i == 0) {
	//						found = this.getMap().isPassable(tmpX, tmpY + 1, i);
	//					} else if (i == 1) {
	//						found = this.getMap().isPassable(tmpX - 1, tmpY + 1, i);
	//					} else if (i == 2) {
	//						found = this.getMap().isPassable(tmpX - 1, tmpY, i);
	//					} else if (i == 3) {
	//						found = this.getMap().isPassable(tmpX - 1, tmpY - 1, i);
	//					} else if (i == 4) {
	//						found = this.getMap().isPassable(tmpX, tmpY - 1, i);
	//					}
	//					if (found) // 移動経路があった場合
	//					{
	//						locCopy = new int[4];
	//						System.arraycopy(locNext, 0, locCopy, 0, 4);
	//						locCopy[2] = dirFront[i];
	//						queueSerch.add(locCopy);
	//					}
	//					serchMap[locNext[0]][locNext[1]] = false;
	//				}
	//			}
	//			locBace = null;
	//		}
	//		return -1; // 目標までの経路がない場合
	//	}

	//	// ＡＩの処理 (返り値はＡＩ処理を終了するかどうか)
	//	private boolean AIProcess() {
	//		this.setSleepTime(300);
	//
	//		this.checkTarget();
	//		if (this._target == null && this._master == null) {
	//			// 空っぽの場合はターゲットを探してみる
	//			// （主人がいる場合は自分でターゲットを探さない）
	//			this.searchTarget();
	//		}
	//
	//		this.onItemUse();
	//
	//		if (this._target == null) {
	//			// ターゲットがいない場合
	//			this.checkTargetItem();
	//			if (this.isPickupItem() && this._targetItem == null) {
	//				// アイテム拾う子の場合はアイテムを探してみる
	//				this.searchTargetItem();
	//			}
	//
	//			if (this._targetItem == null) {
	//				if (this.noTarget()) {
	//					return true;
	//				}
	//			} else {
	//				// onTargetItem();
	//				final L1Inventory groundInventory = L1World.getInstance().getInventory(this._targetItem.getX(), this._targetItem.getY(),this._targetItem.getMapId());
	//				if (groundInventory.checkItem(this._targetItem.getItemId())) {
	//					this.onTargetItem();
	//				} else {
	//					this._targetItemList.remove(this._targetItem);
	//					this._targetItem = null;
	//					this.setSleepTime(1000);
	//					return false;
	//				}
	//			}
	//		} else { // ターゲットがいる場合
	//			if (this.getHiddenStatus() == HIDDEN_STATUS_NONE) {
	//				this.onTarget();
	//			} else {
	//				return true;
	//			}
	//		}
	//
	//		return false; // ＡＩ処理続行
	//	}

	// 全てのターゲットを削除
	public void allTargetClear() {
		if (this._npcMove != null) {
			this._npcMove.clear();
		}
		this._hateList.clear();
		this._dropHateList.clear();
		this._target = null;
		this._targetItemList.clear();
		this._targetItem = null;
	}

	public void appearOnGround(final L1PcInstance pc) {
		if (this.getHiddenStatus() == HIDDEN_STATUS_SINK) {
			//TODO 修正水晶洞穴解凍動作by9001183ex
			//刪除|| getHiddenStatus() == HIDDEN_STATUS_ICE) {
			//TODO 修正水晶洞穴解凍動作by9001183ex
			this.setHiddenStatus(HIDDEN_STATUS_NONE);
			this.broadcastPacketAll(new S_DoActionGFX(this.getId(),ActionCodes.ACTION_Appear));
			this.setStatus(0);
			if(pc.isGm()){
				this.broadcastPacketAll(new S_NPCPack(this));
				if (!pc.hasSkillEffect(60) && !pc.hasSkillEffect(97)) { // インビジビリティ、ブラインドハイディング中以外、GM以外
					this._hateList.add(pc, 0);
					this._target = pc;
				}
			}

			this.onNpcAI(); // モンスターのＡＩを開始

			//TODO 修正水晶洞穴解凍動作by9001183ex
		} else if (this.getHiddenStatus() == HIDDEN_STATUS_ICE) {
			this.setHiddenStatus(HIDDEN_STATUS_NONE);
			this.broadcastPacketAll(new S_DoActionGFX(this.getId(), 11));
			this.setStatus(0);
			if(pc.isGm()){
				this.broadcastPacketAll(new S_NPCPack(this));
				if (!pc.hasSkillEffect(60) && !pc.hasSkillEffect(97)) {
					this._hateList.add(pc, 0);
					this._target = pc;
				}
			}

			this.onNpcAI(); //TODO ＡＩ開始
			//TODO 修正水晶洞穴解凍動作by9001183ex

		} else if (this.getHiddenStatus() == HIDDEN_STATUS_FLY) {
			this.setHiddenStatus(HIDDEN_STATUS_NONE);
			this.broadcastPacketAll(new S_DoActionGFX(this.getId(),ActionCodes.ACTION_Movedown));
			this.setStatus(0);
			if(pc.isGm()){
				this.broadcastPacketAll(new S_NPCPack(this));
				if (!pc.hasSkillEffect(60) && !pc.hasSkillEffect(97)) { // インビジビリティ、ブラインドハイディング中以外、GM以外

					this._hateList.add(pc, 0);
					this._target = pc;
				}
			}

			this.onNpcAI(); // モンスターのＡＩを開始
			this.startChat(CHAT_TIMING_HIDE);
		}
	}

	public void approachPlayer(final L1PcInstance pc) {
		if (pc.hasSkillEffect(60) || pc.hasSkillEffect(97)) { // インビジビリティ、ブラインドハイディング中
			return;
		}
		if (this.getHiddenStatus() == HIDDEN_STATUS_SINK) {
			if (this.getCurrentHp() == this.getMaxHp()) {
				if (pc.getLocation().getTileLineDistance(this.getLocation()) <= 2) {
					this.appearOnGround(pc);
				}
			}
		} else if (this.getHiddenStatus() == HIDDEN_STATUS_FLY) {
			if (this.getCurrentHp() == this.getMaxHp()) {
				if (pc.getLocation().getTileLineDistance(this.getLocation()) <= 1) {
					this.appearOnGround(pc);
				}
			} else {
				// if (getNpcTemplate().get_npcId() != 45681) { // リンドビオル以外
				this.searchItemFromAir();
				// }
			}
		} else if (this.getHiddenStatus() == HIDDEN_STATUS_ICE) {
			if (this.getCurrentHp() < this.getMaxHp()) {
				this.appearOnGround(pc);
			}
		}
	}

	// 目標を指定のスキルで攻撃
	public void attackTarget(final L1Character target) {

		if (target instanceof L1PcInstance) {
			final L1PcInstance player = (L1PcInstance) target;
			if (player.isTeleport()) { // テレポート処理中
				return;
			}
		} else if (target instanceof L1PetInstance) {
			final L1PetInstance pet = (L1PetInstance) target;
			final L1Character cha = pet.getMaster();
			if (cha instanceof L1PcInstance) {
				final L1PcInstance player = (L1PcInstance) cha;
				if (player.isTeleport()) { // テレポート処理中
					return;
				}
			}
		} else if (target instanceof L1SummonInstance) {
			final L1SummonInstance summon = (L1SummonInstance) target;
			final 	L1Character cha = summon.getMaster();
			if (cha instanceof L1PcInstance) {
				final L1PcInstance player = (L1PcInstance) cha;
				if (player.isTeleport()) { // テレポート処理中
					return;
				}
			}
		}
		if (this instanceof L1PetInstance) {
			final L1PetInstance pet = (L1PetInstance) this;
			final L1Character cha = pet.getMaster();
			if (cha instanceof L1PcInstance) {
				final L1PcInstance player = (L1PcInstance) cha;
				if (player.isTeleport()) { // テレポート処理中
					return;
				}
			}
		} else if (this instanceof L1SummonInstance) {
			final L1SummonInstance summon = (L1SummonInstance) this;
			final L1Character cha = summon.getMaster();
			if (cha instanceof L1PcInstance) {
				final L1PcInstance player = (L1PcInstance) cha;
				if (player.isTeleport()) { // テレポート処理中
					return;
				}
			}
			/**警衛抓人下地獄 opqlo**/
		} else if (this instanceof L1GuardInstance && this.getNpcId() == 710061 ){
			if (target instanceof L1PcInstance) {
				final L1PcInstance pc = (L1PcInstance) target;
				if(pc.isWanted()){
					if (pc.isTeleport()) { // テレポート処理中
						return;
					}
					if(!pc.isDead() && pc.getCurrentHp() >0 && pc.get_PKcount()>=30){
						pc.beginHell();
						this.allTargetClear();
						return;
					}
				}
			}
		}

		if (target instanceof L1NpcInstance) {
			final L1NpcInstance npc = (L1NpcInstance) target;
			if (npc.getHiddenStatus() != HIDDEN_STATUS_NONE) { // 地中に潜っているか、飛んでいる
				this.allTargetClear();
				return;
			}
		}

		boolean isCounterBarrier = false;
		final L1AttackModel attack = new L1AttackNpc(this, target);
		if (attack.calcHit()) {
			if (target.hasSkillEffect(COUNTER_BARRIER)) {
				final L1Magic magic = new L1Magic(target, this);
				final boolean isProbability = magic.calcProbabilityMagic(COUNTER_BARRIER);
				final boolean isShortDistance = attack.isShortDistance();
				if (isProbability && isShortDistance) {
					isCounterBarrier = true;
				}
			}
			if (!isCounterBarrier) {
				//TODO 怪物說話-怪物攻擊說話   use 丫傑 code 3/3
				MobTalk.getInstance().forL1MonsterTalking(this, 2);
				attack.calcDamage();
			}
		}
		if (isCounterBarrier) {
			attack.actionCounterBarrier();
			attack.commitCounterBarrier();
		} else {
			attack.action();
			attack.commit();
		}
		this.setSleepTime(this.calcSleepTime(this.getAtkspeed(), ATTACK_SPEED));
	}

	/**
	 * NPC速計算
	 * @param sleepTime 原始數據
	 * @param type 0:通常 1:加速 2:減速
	 * @return 應該延遲的毫秒
	 */
	public int calcSleepTime(int sleepTime, final int type) {
		if (sleepTime <= 0) {
			sleepTime = 960;
		}
		switch (this.getMoveSpeed()) {
		case 0: // 通常
			break;

		case 1: // 加速
			sleepTime -= sleepTime * 0.25;
			break;

		case 2: // 減速
			sleepTime *= 2;
			break;
		}
		if (this.getBraveSpeed() == 1) {// 具有勇水狀態
			sleepTime -= sleepTime * 0.25;
		}
		if (this.hasSkillEffect(WIND_SHACKLE)) {
			if (type == ATTACK_SPEED || type == MAGIC_SPEED) {
				sleepTime += sleepTime * 0.25;
			}
		}
		return sleepTime;
	}

	/**
	 * 有效目標檢查
	 */
	public void checkTarget() {
		try {
			if (_target == null) {// 目標為空
				this.clearTagert();
				return;
			}
			if (_target.getMapId() != getMapId()) {// 目標地圖不相等
				this.clearTagert();
				return;
			}
			if (_target.getCurrentHp() <= 0) {// 目標HP小於等於0
				this.clearTagert();
				return;
			}
			if (_target.isDead()) {// 目標死亡
				this.clearTagert();
				return;
			}
			if (_target.isInvisble() && // 目標已經隱身
					!getNpcTemplate().is_agrocoi() && // 不具備探查隱身能力
					!_hateList.containsKey(_target)) {// 目標不在已有攻擊清單中
				this.clearTagert();
				return;
			}

			final int distance = getLocation().getTileDistance(_target.getLocation());
			if (distance > 30) {
				this.clearTagert();
				return;
			}
		} catch (Exception e) {
			_log.log(Level.SEVERE , e.getLocalizedMessage(), e);
		}
	}
	/**
	 * 清除無效目標<BR>
	 * 搜尋新目標
	 */
	private void clearTagert() {
		if (_target != null) {
			// 清除目標
			tagertClear();
		}

		if (!_hateList.isEmpty()) {
			_target = _hateList.getMaxHateCharacter();
			checkTarget();
		}
	}

	/**
	 * 檢取目標有效判斷
	 */
	public void checkTargetItem() {
		if (this._targetItem == null
				|| this._targetItem.getMapId() != this.getMapId()
				|| this.getLocation().getTileDistance(this._targetItem.getLocation()) > 15) {
			// 具有目標元素
			if (!this._targetItemList.isEmpty()) {
				this._targetItem = this._targetItemList.get(0);
				this._targetItemList.remove(0);
				this.checkTargetItem();// 重新檢查目標物品
			} else {
				this._targetItem = null;
			}
		}
	}

	public void deleteMe() {
		if (this._destroyed) {
			return;
		}

		this._destroyed = true;
		if (this.getInventory() != null) {
			this.getInventory().clearItems();
		}

		this.allTargetClear();
		this._master = null;

		if(this instanceof L1DollInstance == false){
			this.getMap().setPassable(this.getX(), this.getY(), true);
		}

		// 是否具有隊伍
		final L1MobGroupInfo mobGroupInfo = this.getMobGroupInfo();
		if (mobGroupInfo == null) {
			if (this.isReSpawn()) {
				this.onDecay(true);
			}
		} else {
			if (mobGroupInfo.removeMember(this) == 0) { // グループメンバー全滅
				this.setMobGroupInfo(null);
				if (this.isReSpawn()) {
					this.onDecay(false);
				}
			}
		}
		// 清空清單
		_hateList.clear();
		_dropHateList.clear();
		_targetItemList.clear();

		L1World.getInstance().removeVisibleObject(this);
		L1World.getInstance().removeObject(this);

		// 畫面內可見範圍物件取回
		final List<L1PcInstance> players = L1World.getInstance().getRecognizePlayer(this);
		if (players.size() > 0) {
			for (final L1PcInstance tgpc : players) {
				if (tgpc != null) {
					tgpc.removeKnownObject(this);
					// 移除顯示
					tgpc.sendPackets(new S_RemoveObject(this));
				}
			}
		}
		// 認識消除
		this.removeAllKnownObjects();
	}
	/**
	 * 進行刪除
	 * @return true:進行刪除 false:無
	 */
	public boolean destroyed() {
		return this._destroyed;
	}

	public int drainMana(final int drain) {
		if (this._drainedMana >= Config.MANA_DRAIN_LIMIT_PER_NPC) {
			return 0;
		}
		int result = Math.min(drain, this.getCurrentMp());
		if (this._drainedMana + result > Config.MANA_DRAIN_LIMIT_PER_NPC) {
			result = Config.MANA_DRAIN_LIMIT_PER_NPC - this._drainedMana;
		}
		this._drainedMana += result;
		return result;
	}

	public boolean forDropitems() {
		return this._forDropitems;
	}

	/**
	 * 死亡時間(秒)
	 * @return
	 */
	public int get_deadTimerTemp() {
		return this._deadTimerTemp;
	}

	public int getAtkspeed() {
		return this._atkspeed;
	}

	public L1HateList getHateList() {
		return this._hateList;
	}

	public int getHiddenStatus() {
		return this._hiddenStatus;
	}

	public int getHomeX() {
		return this._homeX;
	}

	public int getHomeY() {
		return this._homeY;
	}

	@Override
	public L1Inventory getInventory() {
		return this._inventory;
	}

	public int getLightSize() {
		return this._lightSize;
	}

	// マスターの取得
	public L1Character getMaster() {
		return this._master;
	}

	public int getMobGroupId() {
		return this._mobGroupId;
	}

	public L1MobGroupInfo getMobGroupInfo() {
		return this._mobGroupInfo;
	}

	/**
	 * 移動數據
	 */
	public NpcMoveExecutor getMove() {
		return this._npcMove;
	}

	public int getMovementDistance() {
		return this._movementDistance;
	}

	public String getNameId() {
		return this._nameId;
	}

	public int getNpcId() {
		return this._npcTemplate.get_npcId();
	}

	public L1Npc getNpcTemplate() {
		return this._npcTemplate;
	}

	public int getParalysisTime() {
		return this._paralysisTime;
	}

	public int getPassispeed() {
		return this._passispeed;
	}

	public int getPetcost() {
		return this._petcost;
	}

	protected int getSleepTime() {
		return this._sleep_time;
	}

	public L1Spawn getSpawn() {
		return this._spawn;
	}

	// ■■■■■■■■■■■■■ 移動関連 ■■■■■■■■■■■

	public int getSpawnNumber() {
		return this._spawnNumber;
	}

	public int getTempLawful() {
		return this._tempLawful;
	}

	public void giveDropItems(final boolean i) {
		this._forDropitems = i;
	}
	//TODO 守護神給道具順序by seroidv

	/**
	 * 現在目標
	 */
	public L1Character is_now_target() {
		return this._target;
	}

	/**
	 * 現在目標(物品)
	 */
	public L1ItemInstance is_now_targetItem() {
		return this._targetItem;
	}

	protected boolean isActived() {
		return this._actived;
	}

	public boolean isAgro() {
		return this._Agro;
	}

	public boolean isAgrocoi() {
		return this._Agrocoi;
	}

	public boolean isAgrososc() {
		return this._Agrososc;
	}

	// 移動關聯

	/**
	 * NPC AI時間軸 正在運行
	 * @return
	 */
	protected boolean isAiRunning() {
		return this._aiRunning;
	}

	// ■■■■■■■■■■■■ アイテム関連 ■■■■■■■■■■



	public boolean isDropitems() {
		return this._isDropitems;
	}
	//	private boolean isExsistCharacterBetweenTarget(final int dir) {
	//		if (!(this instanceof L1MonsterInstance)) { // モンスター以外は対象外
	//			return false;
	//		}
	//		if (this._target == null) { // ターゲットがいない場合
	//			return false;
	//		}
	//
	//		final int locX = this.getX();
	//		final int locY = this.getY();
	//		int targetX = locX;
	//		int targetY = locY;
	//
	//		if (dir == 1) {
	//			targetX +=  1;
	//			targetY -=  1;
	//		} else if (dir == 2) {
	//			targetX += 1;
	//		} else if (dir == 3) {
	//			targetX += 1;
	//			targetY += 1;
	//		} else if (dir == 4) {
	//			targetY += 1;
	//		} else if (dir == 5) {
	//			targetX -= 1;
	//			targetY += 1;
	//		} else if (dir == 6) {
	//			targetX -= 1;
	//		} else if (dir == 7) {
	//			targetX -= 1;
	//			targetY -= 1;
	//		} else if (dir == 0) {
	//			targetY -= 1;
	//		}
	//
	//		for (final L1Object object : L1World.getInstance().getVisibleObjects(this, 1)) {
	//			// PC, Summon, Petがいる場合
	//			if (object instanceof L1PcInstance
	//					|| object instanceof L1SummonInstance
	//					|| object instanceof L1PetInstance) {
	//				final L1Character cha = (L1Character) object;
	//				// 進行方向に立ちふさがっている場合、ターゲットリストに加える
	//				if (cha.getX() == targetX && cha.getY() == targetY
	//						&& cha.getMapId() == this.getMapId()) {
	//					if (object instanceof L1PcInstance) {
	//						final 	L1PcInstance pc = (L1PcInstance) object;
	//						if (pc.isGhost()) { // UB観戦中のPCは除く
	//							continue;
	//						}
	//					}
	//					this._hateList.add(cha, 0);
	//					this._target = cha;
	//					return true;
	//				}
	//			}
	//		}
	//		return false;
	//	}
	protected boolean isFirstAttack() {
		return this._firstAttack;
	}
	public boolean isInMobGroup() {
		return this.getMobGroupInfo() != null;
	}

	public boolean isPickupItem() {
		return this._pickupItem;
	}

	// ■■■■■■■■■■■■■ スキル関連(npcskillsテーブル実装されたら消すかも) ■■■■■■■■■■■

	public boolean isReSpawn() {
		return this._reSpawn;
	}

	/**
	 * NPC 動作暫停
	 * @return
	 */
	public boolean isRest() {
		return this._rest;
	}

	/**
	 * 是復活過的
	 * @return
	 */
	public boolean isResurrect() {
		return this._isResurrect;
	}

	public boolean isWeaponBreaked() {
		return this._weaponBreaked;
	}
	//
	//	public int moveDirection(final int x,final int y) { // 目標点Ｘ 目標点Ｙ
	//		return this.moveDirection(x, y,this.getLocation().getLineDistance(new Point(x, y)));
	//	}

	protected L1MobSkillUse mobSkill() {
		return this._mobSkill;
	}

	//	// 目標までの距離に応じて最適と思われるルーチンで進む方向を返す
	//	public int moveDirection(final int x, final int y, final double d) { // 目標点Ｘ 目標点Ｙ 目標までの距離
	//		int dir = 0;
	//		if (this.hasSkillEffect(40) == true && d >= 2D) { // ダークネスが掛かっていて、距離が2以上の場合追跡終了
	//			return -1;
	//		} else if (d > 30D) { // 距離が激しく遠い場合は追跡終了
	//			return -1;
	//		} else if (d > courceRange) { // 距離が遠い場合は単純計算
	//			dir = this.targetDirection(x, y);
	//			dir = checkObject(this.getX(), this.getY(), this.getMapId(), dir);
	//		} else { // 目標までの最短経路を探索
	//			dir = this._serchCource(x, y);
	//			if (dir == -1) { // 目標までの経路がなっかた場合はとりあえず近づいておく
	//				dir = this.targetDirection(x, y);
	//				if (!this.isExsistCharacterBetweenTarget(dir)) {
	//					dir = checkObject(this.getX(), this.getY(), this.getMapId(), dir);
	//				}
	//			}
	//		}
	//		return dir;
	//	}

	/**
	 * 目標鄰近位置指定傳送
	 * @param nx
	 * @param ny
	 * @return
	 */
	public boolean nearTeleport(int nx, int ny) {
		final int rdir = Random.nextInt(8);
		int dir;
		for (int i = 0; i < 8; i++) {
			dir = rdir + i;
			if (dir > 7) {
				dir -= 8;
			}
			nx += HEADING_TABLE_X[dir];;
			ny += HEADING_TABLE_Y[dir];

			if (this.getMap().isPassable(nx, ny, this)) {
				dir += 4;
				if (dir > 7) {
					dir -= 8;
				}
				this.teleport(nx, ny, dir);
				this.setCurrentMp(this.getCurrentMp() - 10);
				return true;
			}
		}
		return false;
	}

	/**
	 * 沒有目標的處理 (傳回本次AI是否執行完成)<BR>
	 * 具有主人 跟隨主人移動
	 *
	 * @return true:本次AI執行完成 <BR>
	 * 			false:本次AI執行未完成
	 */
	public boolean noTarget() {
		if (this._master != null && this._master.getMapId() == this.getMapId()
				&& this.getLocation().getTileLineDistance(this._master.getLocation()) > 2) {
			// 具備移動速度
			if (this.getPassispeed() > 0) {
				if (this._npcMove != null) {
					// 跟隨主人移動
					final int dir = this._npcMove.moveDirection(this._master.getX(), this._master.getY());
					if (dir != -1) {
						this._npcMove.setDirectionMove(dir);
						this.setSleepTime(this.calcSleepTime(this.getPassispeed(), MOVE_SPEED));

					} else {
						return true;
					}
				} else {
					return true;
				}
			}

		} else {
			// 週邊無PC物件 AI處理終止
			if (L1World.getInstance().getVisiblePlayer(this, DISTANCE).size() <= 0) {
				this.teleport(this.getHomeX(), this.getHomeY(), this.getHeading());
				return true;
			}
			// 沒有隊長 具有移動速度 並未動作暫停
			if (this._master == null && this.getPassispeed() > 0 && !this.isRest()) {
				// NPC不具有隊伍狀態
				final L1MobGroupInfo mobGroupInfo = this.getMobGroupInfo();
				if (mobGroupInfo == null || mobGroupInfo != null && mobGroupInfo.isLeader(this)) {

					// 如果移動距離已經為0 重新定義隨機移動
					if (this._randomMoveDistance == 0) {
						// 產生移動距離
						this._randomMoveDistance = Random.nextInt(3) + 1;

						// 產生移動方向(隨機數值超出7物件會暫停移動)
						this._randomMoveDirection = Random.nextInt(40);

						// 返回出生點的判斷
						if (this.getHomeX() != 0 && this.getHomeY() != 0// 具有出生點設置
								&& this._randomMoveDirection < 8// 具有移動方向
								/*&& (_random.nextInt(3) == 0)*/) {// 隨機產生0
							if (this._npcMove != null) {
								this._randomMoveDirection = this._npcMove.moveDirection(this.getHomeX(), this.getHomeY());
							}
						}

					} else {
						this._randomMoveDistance--;
					}

					if (this._npcMove != null) {
						if (this._randomMoveDirection < 8) {
							int dir = this._npcMove.checkObject(this._randomMoveDirection);
							dir = this._npcMove.openDoor(dir);

							if (dir != -1) {
								this._npcMove.setDirectionMove(dir);
								this.setSleepTime(this.calcSleepTime(this.getPassispeed(), MOVE_SPEED));
							}
						}
					}
				} else {
					// 領隊追尋
					final L1NpcInstance leader = mobGroupInfo.getLeader();
					if (this.getPassispeed() > 0) {
						if (this.getLocation().getTileLineDistance(leader.getLocation()) > 2) {
							if (this._npcMove != null) {
								final int dir = this._npcMove.moveDirection(leader.getX(), leader.getY());
								if (dir == -1) {
									return true;
								} else {
									this._npcMove.setDirectionMove(dir);
									this.setSleepTime(this.calcSleepTime(this.getPassispeed(), MOVE_SPEED));
								}
							}
						}
					}
				}
			}
		}
		return false;
	}

	// 延遲時間
	public void npcSleepTime(final int i, final int type) {
		this.setSleepTime(this.calcSleepTime(SprTable.getInstance().getSprSpeed(this.getTempCharGfx(), i), type));
	}

	/**
	 * 世界物件編號是否再利用
	 * @param isReuseId
	 */
	public void onDecay(final boolean isReuseId) {
		int id = 0;
		if (isReuseId) {
			id = this.getId();

		} else {
			id = 0;
		}
		this._spawn.executeSpawnTask(this._spawnNumber, id);
	}

	public void onFinalAction(final L1PcInstance pc,final  String s) {
	}

	public void onGetItem(final L1ItemInstance item) {
		this.refineItem();
		this.getInventory().shuffle();
		if (this.getNpcTemplate().get_digestitem() > 0) {
			this.setDigestItem(item);
		}
	}

	// アイテム使用処理（Ｔｙｐｅによって結構違うのでオーバライドで実装）
	public void onItemUse() {
	}

	// ＡＩトリガ
	public void onNpcAI() {
	}

	/**
	 * 接觸資訊
	 */
	@Override
	public void onPerceive(final L1PcInstance perceivedFrom) {
		try {
			perceivedFrom.addKnownObject(this);
			if(perceivedFrom.isGm()){
				perceivedFrom.sendPackets(new S_NPCPack(this,false));
			}else{
				perceivedFrom.sendPackets(new S_NPCPack(this));
			}
			this.onNpcAI();

		} catch (final Exception e) {
			_log.log(Level.SEVERE,e.getLocalizedMessage(), e);
		}
	}

	//TODO 實裝 牛 豬 雞 鴨 對話 use srwh code 2/2
	@Override
	public void onTalkAction(final L1PcInstance player) {
		final int objid = this.getId();
		player.set_currentState(L1Character.STATE_IDLE);
		final int npcid = this.getNpcTemplate().get_npcId();
		switch(npcid){
		case 70981://TODO 母雞的編號
			player.sendPackets(new S_NPCTalkReturn(objid, "hen1"));
			break;
		case 70982://TODO 鴨子的編號(L1Npc)
		case 45015://TODO 鴨子的編號(L1Monster)
			player.sendPackets(new S_NPCTalkReturn(objid, "duck1"));
			break;
		case 70983://TODO 豬的編號
			player.sendPackets(new S_NPCTalkReturn(objid, "pig1"));
			break;
		case 70984://TODO 牛的編號
			player.sendPackets(new S_NPCTalkReturn(objid, "milkcow1"));
			break;
		}
	}
	//TODO 實裝 牛 豬 雞 鴨 對話 use srwh code 2/2

	// ターゲットがいる場合の処理
	public void onTarget() {
		this.setActived(true);
		this._targetItemList.clear();
		this._targetItem = null;
		final L1Character target = this._target; // ここから先は_targetが変わると影響出るので別領域に参照確保
		if (this.getAtkspeed() == 0) { // 逃げるキャラ
			//TODO 補上怪物移動判斷by
			if (this.getPassispeed() > 0) { // 移動できるキャラ
				//TODO 補上怪物移動判斷by
				//TODO 怪物說話-怪物逃跑說話by  阿傑
				MobTalk.getInstance().forL1MonsterTalking(this, 4);
				//TODO 怪物說話-怪物逃跑說話by  阿傑
				int escapeDistance = 15;
				if (this.hasSkillEffect(40) == true) {
					escapeDistance = 1;
				}
				if (this.getLocation().getTileLineDistance(target.getLocation()) > escapeDistance) { // ターゲットから逃げるの終了
					this.tagertClear();
				} else { // ターゲットから逃げる
					int dir = this._npcMove.targetReverseDirection(target.getX(), target.getY());
					dir = this._npcMove.checkObject(dir);
					dir = this._npcMove.openDoor(dir);
					this._npcMove.setDirectionMove(dir);
					this.setSleepTime(this.calcSleepTime(this.getPassispeed(), MOVE_SPEED));
				}
			}
		} else { // 逃げないキャラ
			if (this.isAttackPosition(target.getX(), target.getY(), this.getNpcTemplate().get_ranged())) { // 攻撃可能位置
				if (this._mobSkill.isSkillTrigger(target)) { // トリガの条件に合うスキルがある
					if (Random.nextInt(2) >= 1) { // 一定の確率で物理攻撃
						this.setHeading(this.targetDirection(target.getX(), target.getY()));
						this.attackTarget(target);
					} else {
						if (this._mobSkill.skillUse(target, true)) { // スキル使用(mobskill.sqlのTriRndに従う)
							this.setSleepTime(this.calcSleepTime(this._mobSkill.getSleepTime(),MAGIC_SPEED));
						} else { // スキル使用が失敗したら物理攻撃
							this.setHeading(this.targetDirection(target.getX(),target.getY()));
							this.attackTarget(target);
						}
					}
				} else {
					this.setHeading(this.targetDirection(target.getX(), target.getY()));
					this.attackTarget(target);
				}
				if (this._npcMove != null) {
					this._npcMove.clear();
				}
			} else { // 攻撃不可能位置
				if (this._mobSkill.skillUse(target, false)) { // スキル使用(mobskill.sqlのTriRndに従わず、発動確率は100%。ただしサモン、強制変身は常にTriRndに従う。)
					this.setSleepTime(this.calcSleepTime(this._mobSkill.getSleepTime(),MAGIC_SPEED));
					return;
				}

				if (this.getPassispeed() > 0) {
					// 移動できるキャラ
					final int distance = this.getLocation().getTileDistance(target.getLocation());
					if (this.firstFound == true && this.getNpcTemplate().is_teleport()
							&& distance > 3 && distance < 15) {
						if (this.nearTeleport(target.getX(), target.getY()) == true) {
							this.firstFound = false;
							return;
						}
					}

					if (this.getNpcTemplate().is_teleport()
							&& 20 > Random.nextInt(100)
							&& this.getCurrentMp() >= 10 && distance > 6
							&& distance < 15) { // テレポート移動
						if (this.nearTeleport(target.getX(), target.getY()) == true) {
							return;
						}
					}

					if (this._npcMove != null) {
						final int dir = this._npcMove.moveDirection(target.getX(), target.getY());
						if (dir == -1) {
							this.tagertClear();

						} else {
							this._npcMove.setDirectionMove(dir);
							this.setSleepTime(this.calcSleepTime(this.getPassispeed(), MOVE_SPEED));
						}
					}
				} else {
					// 移動できないキャラ（ターゲットから排除、ＰＴのときドロップチャンスがリセットされるけどまぁ自業自得）
					this.tagertClear();
				}
			}
		}
	}

	/**
	 * 物品檢取的判斷
	 */
	public void onTargetItem() {
		if (this.getLocation().getTileLineDistance(this._targetItem.getLocation()) == 0) { // 抵達可撿取物品位置
			this.pickupTargetItem(this._targetItem);

		} else { // 尚未抵達可撿取物品位置
			if (this._npcMove != null) {
				final int dir = this._npcMove.moveDirection(this._targetItem.getX(), this._targetItem.getY());
				if (dir == -1) { // 拾うの諦め
					this._targetItemList.remove(this._targetItem);
					this._targetItem = null;

				} else { // ターゲットアイテムへ移動
					this._npcMove.setDirectionMove(dir);
					this.setSleepTime(this.calcSleepTime(this.getPassispeed(), MOVE_SPEED));
				}
			}
		}
	}

	/**
	 * 檢取物品
	 * @param targetItem
	 */
	public void pickupTargetItem(final L1ItemInstance targetItem) {
		try {
			final int x = targetItem.getX();
			final int y = targetItem.getY();
			final short m = targetItem.getMapId();
			final L1Inventory groundInv =
					L1World.getInstance().getInventory(x, y, m);
			final L1ItemInstance item =
					groundInv.tradeItem(targetItem, targetItem.getCount(), this.getInventory());
			//turnOnOffLight();
			this.onGetItem(item);
			this._targetItemList.remove(this._targetItem);
			this._targetItem = null;
			this.setSleepTime(1000);

		} catch (final Exception e) {
			_log.log(Level.SEVERE ,e.getLocalizedMessage(), e);
		}
	}

	public void receiveDamage(final L1Character attacker,final  int damage) {
	}

	public void ReceiveManaDamage(final L1Character attacker,final  int damageMp) {
	}

	// アイテム精製
	public void refineItem() {

		int[] materials = null;
		int[] counts = null;
		int[] createitem = null;
		int[] createcount = null;

		if (this._npcTemplate.get_npcId() == 45032) { // ブロッブ
			// オリハルコンソードの刀身
			final boolean exp = this.getExp() != 0;
			if(exp){
				if ( !this._inventory.checkItem(20)) {
					materials = new int[] { 40508, 40521, 40045 };
					counts = new int[] { 150, 3, 3 };
					createitem = new int[] { 20 };
					createcount = new int[] { 1 };
					if (this._inventory.checkItem(materials, counts)) {
						for (int i = 0; i < materials.length; i++) {
							this._inventory.consumeItem(materials[i], counts[i]);
						}
						for (int j = 0; j < createitem.length; j++) {
							this._inventory.storeItem(createitem[j], createcount[j]);
						}
					}
				}
				// ロングソードの刀身
				if (!this._inventory.checkItem(19)) {
					materials = new int[] { 40494, 40521 };
					counts = new int[] { 150, 3 };
					createitem = new int[] { 19 };
					createcount = new int[] { 1 };
					if (this._inventory.checkItem(materials, counts)) {
						for (int i = 0; i < materials.length; i++) {
							this._inventory.consumeItem(materials[i], counts[i]);
						}
						for (int j = 0; j < createitem.length; j++) {
							this._inventory.storeItem(createitem[j], createcount[j]);
						}
					}
				}
				// ショートソードの刀身
				if (!this._inventory.checkItem(3)) {
					materials = new int[] { 40494, 40521 };
					counts = new int[] { 50, 1 };
					createitem = new int[] { 3 };
					createcount = new int[] { 1 };
					if (this._inventory.checkItem(materials, counts)) {
						for (int i = 0; i < materials.length; i++) {
							this._inventory.consumeItem(materials[i], counts[i]);
						}
						for (int j = 0; j < createitem.length; j++) {
							this._inventory.storeItem(createitem[j], createcount[j]);
						}
					}
				}
				// オリハルコンホーン
				if (!this._inventory.checkItem(100)) {
					materials = new int[] { 88, 40508, 40045 };
					counts = new int[] { 4, 80, 3 };
					createitem = new int[] { 100 };
					createcount = new int[] { 1 };
					if (this._inventory.checkItem(materials, counts)) {
						for (int i = 0; i < materials.length; i++) {
							this._inventory.consumeItem(materials[i], counts[i]);
						}
						for (int j = 0; j < createitem.length; j++) {
							this._inventory.storeItem(createitem[j], createcount[j]);
						}
					}
				}
				// ミスリルホーン
				if (!this._inventory.checkItem(89)) {
					materials = new int[] { 88, 40494 };
					counts = new int[] { 2, 80 };
					createitem = new int[] { 89 };
					createcount = new int[] { 1 };
					if (this._inventory.checkItem(materials, counts)) {
						for (int i = 0; i < materials.length; i++) {
							this._inventory.consumeItem(materials[i], counts[i]);
						}
						for (int j = 0; j < createitem.length; j++) {
							final L1ItemInstance item = this._inventory.storeItem(
									createitem[j], createcount[j]);
							if (this.getNpcTemplate().get_digestitem() > 0) {
								this.setDigestItem(item);
							}
						}
					}
				}
			}
		} else if (this._npcTemplate.get_npcId() == 81069) { // ドッペルゲンガー（クエスト）
			// ドッペルゲンガーの体液
			if (this.getExp() != 0 && !this._inventory.checkItem(40542)) {
				materials = new int[] { 40032 };
				counts = new int[] { 1 };
				createitem = new int[] { 40542 };
				createcount = new int[] { 1 };
				if (this._inventory.checkItem(materials, counts)) {
					for (int i = 0; i < materials.length; i++) {
						this._inventory.consumeItem(materials[i], counts[i]);
					}
					for (int j = 0; j < createitem.length; j++) {
						this._inventory.storeItem(createitem[j], createcount[j]);
					}
				}
			}
		} else if (this._npcTemplate.get_npcId() == 45166 // ジャックオーランタン
				|| this._npcTemplate.get_npcId() == 45167) {
			// パンプキンの種
			if (this.getExp() != 0 && !this._inventory.checkItem(40726)) {
				materials = new int[] { 40725 };
				counts = new int[] { 1 };
				createitem = new int[] { 40726 };
				createcount = new int[] { 1 };
				if (this._inventory.checkItem(materials, counts)) {
					for (int i = 0; i < materials.length; i++) {
						this._inventory.consumeItem(materials[i], counts[i]);
					}
					for (int j = 0; j < createitem.length; j++) {
						this._inventory.storeItem(createitem[j], createcount[j]);
					}
				}
			}
		}
	}

	/**
	 * 復活處理
	 */
	@Override
	public synchronized void resurrect(final int hp) {
		if (this._destroyed) {
			return;
		}

		super.resurrect(hp);

		this.startHpRegeneration();
		this.startMpRegeneration();

		// 移出死亡清單
		if (this._deadTimerTemp != -1) {
			this._deadTimerTemp = -1;
		}

		/*if (_deleteTask != null) {
			if (!_future.cancel(false)) { // キャンセルできない
				return;
			}
			_deleteTask = null;
			_future = null;
		}*/

		// キャンセレーションをエフェクトなしでかける
		// 本来は死亡時に行うべきだが、負荷が大きくなるため復活時に行う
		final L1SkillUse skill = new L1SkillUse();
		skill.handleCommands(null, CANCELLATION, this.getId(), this.getX(), this.getY(), null,0, L1SkillUse.TYPE_LOGIN, this);
	}

	/**
	 * 飛んでいる状態からアイテムを探し、あれば降りて拾う
	 */
	public void searchItemFromAir() {
		final ArrayList<L1GroundInventory> gInventorys = new ArrayList<L1GroundInventory>();

		for (final L1Object obj : L1World.getInstance().getVisibleObjects(this)) {
			if (obj != null && obj instanceof L1GroundInventory) {
				gInventorys.add((L1GroundInventory) obj);
			}
		}
		if (gInventorys.size() == 0) {
			return;
		}

		// 拾うアイテム(のインベントリ)をランダムで選定
		final int pickupIndex = (int) (Math.random() * gInventorys.size());
		final L1GroundInventory inventory = gInventorys.get(pickupIndex);
		for (final L1ItemInstance item : inventory.getItems()) {
			if (item.getItem().getType() == 6
					|| item.getItem().getType() == 7) { // food
				if (this.getInventory().checkAddItem(item, item.getCount()) == L1Inventory.OK) {
					if (this.getHiddenStatus() == HIDDEN_STATUS_FLY) {
						this.setHiddenStatus(HIDDEN_STATUS_NONE);
						this.broadcastPacketAll(new S_DoActionGFX(this.getId(), ActionCodes.ACTION_Movedown));
						this.setStatus(0);
						this.broadcastPacketAll(new S_NPCPack(this));
						this.onNpcAI();
						this.startChat(CHAT_TIMING_HIDE);
						this._targetItem = item;
						this._targetItemList.add(this._targetItem);
					}
				}
			}
		}
	}

	/**
	 * npc目標搜尋設置
	 */
	public void searchTarget() {
	}

	// ターゲットアイテムを探す
	public void searchTargetItem() {
		final ArrayList<L1GroundInventory> gInventorys = new ArrayList<L1GroundInventory>();

		for (final L1Object obj : L1World.getInstance().getVisibleObjects(this)) {
			if (obj != null && obj instanceof L1GroundInventory) {
				gInventorys.add((L1GroundInventory) obj);
			}
		}
		if (gInventorys.size() == 0) {
			return;
		}

		// 拾うアイテム(のインベントリ)をランダムで選定
		final int pickupIndex = (int) (Math.random() * gInventorys.size());
		final L1GroundInventory inventory = gInventorys.get(pickupIndex);
		for (final L1ItemInstance item : inventory.getItems()) {
			if (this.getInventory().checkAddItem(item, item.getCount()) == L1Inventory.OK) { // 持てるならターゲットアイテムに加える
				this._targetItem = item;
				this._targetItemList.add(this._targetItem);
			}
		}
	}

	// 仲間意識によりアクティブになるＮＰＣの検索（攻撃者がプレイヤーのみ有効）
	public void serchLink(final L1PcInstance targetPlayer,final int family) {
		final List<L1Object> targetKnownObjects = targetPlayer.getKnownObjects();
		for (final Object knownObject : targetKnownObjects) {
			if (knownObject instanceof L1NpcInstance) {
				final L1NpcInstance npc = (L1NpcInstance) knownObject;
				final L1Npc NpcTemplate = npc.getNpcTemplate();
				if (NpcTemplate.get_agrofamily() > 0) {
					// 仲間に対してアクティブになる場合
					if (NpcTemplate.get_agrofamily() == 1) {
						// 同種族に対してのみ仲間意識
						if (NpcTemplate.get_family() == family) {
							npc.setLink(targetPlayer);
						}
					} else {
						// 全てのＮＰＣに対して仲間意識
						npc.setLink(targetPlayer);
					}
				}
				final L1MobGroupInfo mobGroupInfo = this.getMobGroupInfo();
				if (mobGroupInfo != null) {
					if (this.getMobGroupId() != 0
							&& this.getMobGroupId() == npc.getMobGroupId()) { // 同じグループ
						npc.setLink(targetPlayer);
					}
				}
				//TODO 警衛可以殺死 & 幫打by阿傑
				if(this instanceof L1GuardInstance && knownObject instanceof L1GuardInstance){
					final L1GuardInstance guard = (L1GuardInstance)knownObject;
					if(guard.getCurrentHp()>0){
						guard.setLink(targetPlayer);
					}
				}
				//TODO 警衛可以殺死 & 幫打by阿傑
			}
		}
	}

	/**
	 * 死亡時間(秒)
	 * @param time
	 */
	public void set_deadTimerTemp(int time) {
		this._deadTimerTemp = time;
	}

	/**
	 * 現在目標(物品)
	 */
	public void set_now_targetItem(L1ItemInstance item) {
		this._targetItem = item;
	}

	protected void setActived(final boolean actived) {
		this._actived = actived;
	}

	public void setAgro(final boolean flag) {
		this._Agro = flag;
	}

	public void setAgrocoi(final boolean flag) {
		this._Agrocoi = flag;
	}


	public void setAgrososc(final boolean flag) {
		this._Agrososc = flag;
	}

	/**
	 * NPC AI時間軸 正在運行
	 * @param aiRunning
	 */
	protected void setAiRunning(final boolean aiRunning) {
		this._aiRunning = aiRunning;
	}

	public void setAtkspeed(final int i) {
		this._atkspeed = i;
	}

	private boolean _deathProcessing = false; // 死亡処理中か

	/**
	 * 死亡處理中
	 * @param deathProcessing
	 */
	protected void setDeathProcessing(final boolean deathProcessing) {
		this._deathProcessing = deathProcessing;
	}

	/**
	 * 死亡處理中
	 * @return
	 */
	protected boolean isDeathProcessing() {
		return this._deathProcessing;
	}


	public void setDigestItem(final L1ItemInstance item) {
		this._digestItems.put(new Integer(item.getId()), new Integer(this.getNpcTemplate().get_digestitem()));
		if (!this._digestItemRunning) {
			final DigestItemTimer digestItemTimer = new DigestItemTimer();
			GeneralThreadPool.getInstance().execute(digestItemTimer);
		}
	}

	/*// 指定された方向に移動させる
	public void setDirectionMove(final int dir) {
		if (dir >= 0) {
			int nx = 0;
			int ny = 0;

			switch (dir) {
			case 1:
				nx = 1;
				ny = -1;
				this.setHeading(1);
				break;

			case 2:
				nx = 1;
				ny = 0;
				this.setHeading(2);
				break;

			case 3:
				nx = 1;
				ny = 1;
				this.setHeading(3);
				break;

			case 4:
				nx = 0;
				ny = 1;
				this.setHeading(4);
				break;

			case 5:
				nx = -1;
				ny = 1;
				this.setHeading(5);
				break;

			case 6:
				nx = -1;
				ny = 0;
				this.setHeading(6);
				break;

			case 7:
				nx = -1;
				ny = -1;
				this.setHeading(7);
				break;

			case 0:
				nx = 0;
				ny = -1;
				this.setHeading(0);
				break;

			default:
				break;

			}
			if(!(this instanceof L1DollInstance)){
				this.getMap().setPassable(this.getLocation(), true);
			}
			final int nnx = this.getX() + nx;
			final int nny = this.getY() + ny;
			this.setX(nnx);
			this.setY(nny);
			if(!(this instanceof L1DollInstance)){

				this.getMap().setPassable(this.getLocation(), false);
			}
			this.broadcastPacket(new S_MoveCharPacket(this));

			// movement_distanceマス以上離れたらホームポイントへテレポート
			if (this.getMovementDistance() > 0) {
				if (this instanceof L1GuardInstance
						|| this instanceof L1MerchantInstance
						|| this instanceof L1MonsterInstance) {
					if (this.getLocation().getLineDistance(
							new Point(this.getHomeX(), this.getHomeY())) > this.getMovementDistance()) {
						this.teleport(this.getHomeX(), this.getHomeY(), this.getHeading());
					}
				}
			}
			// 恨みに満ちたソルジャーゴースト、恨みに満ちたゴースト、恨みに満ちたハメル将軍
			if (this.getNpcTemplate().get_npcId() >= 45912
					&& this.getNpcTemplate().get_npcId() <= 45916) {
				if (this.getX() >= 32591 && this.getX() <= 32644 && this.getY() >= 32643
						&& this.getY() <= 32688 && this.getMapId() == 4) {
					this.teleport(this.getHomeX(), this.getHomeY(), this.getHeading());
				}
			}
		}
	}*/
	public void setDropItems(final boolean i) {
		this._isDropitems = i;
	}

	protected void setFirstAttack(final boolean firstAttack) {
		this._firstAttack = firstAttack;
	}

	/**
	 * 攻擊目標設置
	 * @param cha
	 * @param hate
	 */
	public void setHate(final L1Character cha, int hate) {
		try {
			if (cha != null && cha.getId() != this.getId()) {
				if (!this.isFirstAttack() && hate != 0) {
					hate += this.getMaxHp() / 10; // ＦＡヘイト
					this.setFirstAttack(true);
				}
				if (this._npcMove != null) {
					this._npcMove.clear();//XXX
				}

				this._hateList.add(cha, hate);
				this._dropHateList.add(cha, hate);
				this._target = this._hateList.getMaxHateCharacter();
				this.checkTarget();
			}

		} catch (final Exception e) {
			return;
		}
	}

	public void setHiddenStatus(final int i) {
		this._hiddenStatus = i;
	}

	public void setHomeX(final int i) {
		this._homeX = i;
	}

	public void setHomeY(final int i) {
		this._homeY = i;
	}

	public void setInventory(final L1Inventory inventory) {
		this._inventory = inventory;
	}

	public void setLightSize(final int i) {
		this._lightSize = i;
	}

	// リンクの設定
	public void setLink(final L1Character cha) {
	}

	// マスターの設定
	public void setMaster(final L1Character cha) {
		this._master = cha;
	}

	public void setMobGroupId(final int i) {
		this._mobGroupId = i;
	}

	public void setMobGroupInfo(final L1MobGroupInfo m) {
		this._mobGroupInfo = m;
	}
	public void setMovementDistance(final int i) {
		this._movementDistance = i;
	}

	// ※破棄後に動かないよう強制的にＡＩ等のスレッド処理中止（念のため）

	public void setNameId(final String s) {
		this._nameId = s;
	}
	public void setParalysisTime(final int ptime) {
		this._paralysisTime = ptime;
	}
	public void setPassispeed(final int i) {
		this._passispeed = i;
	}

	public void setPetcost(final int i) {
		this._petcost = i;
	}

	public void setPickupItem(final boolean flag) {
		this._pickupItem = flag;
	}

	public void setreSpawn(final boolean flag) {
		this._reSpawn = flag;
	}

	/**
	 * 設置 NPC 動作暫停
	 * @param rest
	 */
	public void setRest(final boolean _rest) {
		this._rest = _rest;
	}
	/**
	 * 是復活過的
	 * @param flag
	 */
	public void setResurrect(final boolean flag) {
		this._isResurrect = flag;
	}

	protected void setSleepTime(final int sleep_time) {
		this._sleep_time = sleep_time;
	}

	public void setSpawn(final L1Spawn spawn) {
		this._spawn = spawn;
	}
	public void setSpawnNumber(final int number) {
		this._spawnNumber = number;
	}

	// 死んでから消えるまでの時間計測用
	//	private DeleteTimer _deleteTask;
	//	private ScheduledFuture<?> _future = null;

	/*	protected synchronized void startDeleteTimer() {
		if (_deleteTask != null) {
			return;
		}
		_deleteTask = new DeleteTimer(getId());
		_future = GeneralThreadPool.getInstance().schedule(_deleteTask,
				Config.NPC_DELETION_TIME * 1000);
	}*/

	/*	protected static class DeleteTimer extends TimerTask {
		private int _id;

		protected DeleteTimer(final int oId) {
			_id = oId;
			if (!(L1World.getInstance().findObject(_id) instanceof L1NpcInstance)) {
				throw new IllegalArgumentException("allowed only L1NpcInstance");
			}
		}

		@Override
		public void run() {
			final L1NpcInstance npc = (L1NpcInstance) L1World.getInstance()
			.findObject(_id);
			if (npc == null || !npc.isDead() || npc._destroyed) {
				return; // 復活してるか、既に破棄済みだったら抜け
			}
			try {
				npc.deleteMe();
			} catch (Exception e) { // 絶対例外を投げないように
				e.printStackTrace();
			}
		}
	}*/

	public void setTempLawful(final int i) {
		this._tempLawful = i;
	}


	// 指定のテンプレートで各種値を初期化
	public void setting_template(final L1Npc template) {
		this._npcTemplate = template;
		int randomlevel = 0;
		double rate = 0;
		double diff = 0;
		this.setName(template.get_name());

		this.setNameId(template.get_nameid());
		this.isBigSize = template.get_size(); //opqlo 怪物大小判斷修改
		this.setExtraDmg(template.getExtraDmg());//opqlo 額外攻擊力
		this.setExtraDef(template.getExtraDef());//opqlo 額外防禦力
		this.setDmgReduceRate(template.getDmgReduceRate());//opqlo 怪物減傷倍率

		if (template.get_randomlevel() == 0) { // ランダムLv指定なし
			this.setLevel(template.get_level());
		} else { // ランダムLv指定あり（最小値:get_level(),最大値:get_randomlevel()）
			randomlevel = Random.nextInt(template.get_randomlevel()- template.get_level() + 1);
			diff = template.get_randomlevel() - template.get_level();
			rate = randomlevel / diff;
			randomlevel += template.get_level();
			this.setLevel(randomlevel);
		}
		if (template.get_randomhp() == 0) {
			this.setMaxHp(template.get_hp());
			this.setCurrentHpDirect(template.get_hp());
		} else {
			final double randomhp = rate
					* (template.get_randomhp() - template.get_hp());
			final int hp = (int) (template.get_hp() + randomhp);
			this.setMaxHp(hp);
			this.setCurrentHpDirect(hp);
		}
		if (template.get_randommp() == 0) {
			this.setMaxMp(template.get_mp());
			this.setCurrentMpDirect(template.get_mp());
		} else {
			final double randommp = rate
					* (template.get_randommp() - template.get_mp());
			final int mp = (int) (template.get_mp() + randommp);
			this.setMaxMp(mp);
			this.setCurrentMpDirect(mp);
		}
		if (template.get_randomac() == 0) {
			this.setAc(template.get_ac());
		} else {
			final double randomac = rate
					* (template.get_randomac() - template.get_ac());
			final int ac = (int) (template.get_ac() + randomac);
			this.setAc(ac);
		}
		if (template.get_randomlevel() == 0) {
			this.setStr(template.get_str());
			this.setCon(template.get_con());
			this.setDex(template.get_dex());
			this.setInt(template.get_int());
			this.setWis(template.get_wis());
			this.setMr(template.get_mr());
		} else {
			this.setStr((short) Math.min(template.get_str() + diff, 255));
			this.setCon((short) Math.min(template.get_con() + diff, 255));
			this.setDex((short) Math.min(template.get_dex() + diff, 255));
			this.setInt((short) Math.min(template.get_int() + diff, 255));
			this.setWis((short) Math.min(template.get_wis() + diff, 255));
			this.setMr((int) Math.min(template.get_mr() + diff, 1000));

			this.addHitup((int) diff * 2);
			this.addDmgup((int) diff * 2);
		}
		this.setPassispeed(template.get_passispeed());
		this.setAtkspeed(template.get_atkspeed());
		this.setAgro(template.is_agro());
		this.setAgrocoi(template.is_agrocoi());
		this.setAgrososc(template.is_agrososc());
		this.setTempCharGfx(template.get_gfxid());
		this.setGfxId(template.get_gfxid());
		if (template.get_randomexp() == 0) {
			this.setExp(template.get_exp());
		} else {
			final int level = this.getLevel();
			this.setExp(level * level +1);
		}
		final int lawful1 =template.get_lawful();
		if (template.get_randomlawful() == 0) {
			this.setLawful(lawful1);
			this.setTempLawful(lawful1);
		} else {
			final double randomlawful = rate
					* (template.get_randomlawful() - lawful1);
			final int lawful = (int) (lawful1 + randomlawful);
			this.setLawful(lawful);
			this.setTempLawful(lawful);
		}
		this.setPickupItem(template.is_picupitem());
		if (template.is_bravespeed()) {
			this.setBraveSpeed(1);
			//			this.setMoveSpeed(1);
		} else {
			this.setBraveSpeed(0);
		}
		if (template.get_digestitem() > 0) {
			this._digestItems = new HashMap<Integer, Integer>();
		}
		this.setKarma(template.getKarma());
		this.setLightSize(template.getLightSize());

		this._mobSkill = new L1MobSkillUse(this);
	}

	public void setWeaponBreaked(final boolean flag) {
		this._weaponBreaked = flag;
	}

	/**
	 * 啟用NPC AI
	 */
	protected void startAI() {
		//		if (Config.NPCAI_IMPLTYPE == 1) {
		//			new NpcAITimerImpl().start();
		//		} else if (Config.NPCAI_IMPLTYPE == 2) {
		//			new NpcAIThreadImpl().start();
		//		} else {
		//			new NpcAITimerImpl().start();
		//		}
		if (this.isDead()) {
			return;
		}
		if (this.destroyed()) {
			return;
		}
		if (this.getCurrentHp() <= 0) {
			return;
		}
		final NpcAI npcai = new NpcAI(this);
		npcai.startAI();

		this.startHpRegeneration();
		this.startMpRegeneration();
	}

	public void startChat(final int chatTiming) {
		// 出現時のチャットにも関わらず死亡中、死亡時のチャットにも関わらず生存中
		if (chatTiming == CHAT_TIMING_APPEARANCE && this.isDead()) {
			return;
		}
		if (chatTiming == CHAT_TIMING_DEAD && !this.isDead()) {
			return;
		}
		if (chatTiming == CHAT_TIMING_HIDE && this.isDead()) {
			return;
		}
		if (chatTiming == CHAT_TIMING_GAME_TIME && this.isDead()) {
			return;
		}

		final int npcId = this.getNpcTemplate().get_npcId();
		L1NpcChat npcChat = null;
		if (chatTiming == CHAT_TIMING_APPEARANCE) {
			npcChat = NpcChatTable.getInstance().getTemplateAppearance(npcId);
		} else if (chatTiming == CHAT_TIMING_DEAD) {
			npcChat = NpcChatTable.getInstance().getTemplateDead(npcId);
		} else if (chatTiming == CHAT_TIMING_HIDE) {
			npcChat = NpcChatTable.getInstance().getTemplateHide(npcId);
		} else if (chatTiming == CHAT_TIMING_GAME_TIME) {
			npcChat = NpcChatTable.getInstance().getTemplateGameTime(npcId);
		}
		if (npcChat == null) {
			return;
		}

		final Timer timer = new Timer(true);
		final L1NpcChatTimer npcChatTimer = new L1NpcChatTimer(this, npcChat);
		if (!npcChat.isRepeat()) {
			timer.schedule(npcChatTimer, npcChat.getStartDelayTime());
		} else {
			timer.scheduleAtFixedRate(npcChatTimer,npcChat.getStartDelayTime(), npcChat.getRepeatInterval());
		}
	}

	/**
	 * 加入NPC死亡清單
	 * @param deltime 刪除時間(秒)
	 */
	protected synchronized void startDeleteTimer() {
		if (this._deadTimerTemp != -1) {
			return;
		}
		this._deadTimerTemp = Config.NPC_DELETION_TIME;
	}

	// ＨＰ自然回復
	private boolean _hprRunning = false;

	//	private HprTimer _hprTimer;

	// ＭＰ自然回復
	private boolean _mprRunning = false;

	//	private MprTimer _mprTimer;

	/**
	 * HP是否具備回復條件
	 * @return
	 */
	public final boolean isHpR() {
		if (this.destroyed()) {// 進行刪除
			return false;
		}

		if (this.isDead()) {// 死亡
			return false;
		}

		if (this.getMaxHp() <= 0) {// 沒有HP設置
			return false;
		}

		if (this.getCurrentHp() <= 0) {// 目前HP小於0
			return false;
		}

		if (this.getCurrentHp() >= this.getMaxHp()) {// HP已滿
			return false;
		}
		return true;
	}

	// HP自然回復
	public final void startHpRegeneration() {
		//		try{
		//			if(!this._hprRunning){
		//				final int hprInterval = this.getNpcTemplate().get_hprinterval();
		//				final int hpr = this.getNpcTemplate().get_hpr();
		//				if (hprInterval > 0 && hpr > 0) {
		//					this._hprRunning = true;
		//					this._hprTimer = new HprTimer(hpr);
		//					L1NpcRegenerationTimer.getInstance().scheduleAtFixedRate(this._hprTimer,hprInterval, hprInterval);
		//				}
		//			}
		//		}catch(Exception e){
		//			_log.log(Level.SEVERE, e.getLocalizedMessage() , e);
		//		}
		if (this.destroyed() && this.isDead()) {
			return;
		}
		if (this.getCurrentHp() <= 0) {
			return;
		}
		if (!this._hprRunning) {
			this._hprRunning = true;
		}
	}

	/**
	 * HP是否允許回復
	 * @return
	 */
	public final boolean isHpRegenerationX() {
		return this._hprRunning;
	}

	/**
	 * 暫停HP回復
	 */
	public final void stopHpRegeneration() {
		if (this._hprRunning) {
			//			this._hprTimer.cancel();
			this._hprRunning = false;
		}
	}

	/**
	 * MP是否具備回復條件
	 * @return
	 */
	public final boolean isMpR() {
		if (this.destroyed()) {// 進行刪除
			return false;
		}

		if (this.isDead()) {// 死亡
			return false;
		}

		if (this.getMaxHp() <= 0) {// 沒有HP設置
			return false;
		}

		if (this.getMaxMp() <= 0) {// 沒有MP設置
			return false;
		}

		if (this.getCurrentHp() <= 0) {// 目前HP小於0
			return false;
		}

		if (this.getCurrentMp() >= this.getMaxMp()) {// MP已滿
			return false;
		}
		return true;
	}

	// MP自然回復
	public final void startMpRegeneration() {
		//		try{
		//			if(!this._mprRunning){
		//				final int mprInterval = this.getNpcTemplate().get_mprinterval();
		//				final int mpr = this.getNpcTemplate().get_mpr();
		//				if (!this._mprRunning && mprInterval > 0 && mpr > 0) {
		//					this._mprRunning = true;
		//					this._mprTimer = new MprTimer(mpr);
		//					L1NpcRegenerationTimer.getInstance().scheduleAtFixedRate(this._mprTimer,mprInterval, mprInterval);
		//				}
		//			}
		//		}catch(Exception e){
		//			_log.log(Level.SEVERE, e.getLocalizedMessage() , e);
		//		}
		if (this.destroyed() && this.isDead()) {
			return;
		}
		if (this.getCurrentHp() <= 0) {
			return;
		}
		if (!this._mprRunning) {
			this._mprRunning = true;
		}
	}

	/**
	 * MP是否允許回復
	 * @return
	 */
	public final boolean isMpRegenerationX() {
		return this._mprRunning;
	}

	/**
	 * 暫停MP回復
	 */
	public final void stopMpRegeneration() {
		if (this._mprRunning) {
			//			this._mprTimer.cancel();
			//			NpcAiThreadPool.get().cancel(_mprTimer);
			this._mprRunning = false;
		}
	}

	// 現在のターゲットを削除
	public void tagertClear() {
		if (this._target == null) {
			return;
		}
		this._hateList.remove(this._target);
		this._target = null;
	}

	// 指定されたターゲットを削除
	public void targetRemove(final L1Character target) {
		this._hateList.remove(target);
		if (this._target != null && this._target.equals(target)) {
			this._target = null;
		}
	}

	// 目標の逆方向を返す
	public int targetReverseDirection(final int tx, final int ty) { // 目標点Ｘ 目標点Ｙ
		int dir = this.targetDirection(tx, ty) +4;

		if (dir > 7) {
			dir -= 8;
		}
		return dir;
	}

	/**
	 * 目標位置指定標傳送
	 * @param nx
	 * @param ny
	 * @param dir
	 */
	public void teleport(final int nx, final int ny,final int dir) {
		try {
			this.getMap().setPassable(this.getX(), this.getY(),true);
			for (final L1PcInstance pc : L1World.getInstance().getRecognizePlayer(this)) {
				pc.sendPackets(new S_SkillSound(this.getId(), 169));
				pc.sendPackets(new S_RemoveObject(this));
				pc.removeKnownObject(this);
			}
			this.setX(nx);
			this.setY(ny);
			this.setHeading(dir);
			this.getMap().setPassable(nx, ny,false);

		} catch (final Exception e) {
			_log.log(Level.SEVERE ,e.getLocalizedMessage(), e);
		}
	}

	// NPCが別のNPCに変わる場合の処理
	protected void transform(final int transformId) {
		this.stopHpRegeneration();
		this.stopMpRegeneration();
		final int transformGfxId = this.getNpcTemplate().getTransformGfxId();
		if (transformGfxId != 0) {
			this.broadcastPacketAll(new S_SkillSound(this.getId(), transformGfxId));
		}
		final L1Npc npcTemplate = NpcTable.getInstance().getTemplate(transformId);
		this.setting_template(npcTemplate);

		this.broadcastPacketAll(new S_ChangeShape(this.getId(), this.getTempCharGfx()));
		for (final L1PcInstance pc : L1World.getInstance().getRecognizePlayer(this)) {
			this.onPerceive(pc);
		}

	}


	private void useHastePotion(final int time) {
		final int id = this.getId();
		this.broadcastPacketAll(new S_SkillHaste(id, 1, time));
		this.broadcastPacketAll(new S_SkillSound(id, 191));
		this.setMoveSpeed(1);
		this.setSkillEffect(STATUS_HASTE, time * 1000);
	}
	private void useHealPotion(int healHp,final int effectId) {
		this.broadcastPacketAll(new S_SkillSound(this.getId(), effectId));
		if (this.hasSkillEffect(POLLUTE_WATER)) { // ポルートウォーター中は回復量1/2倍
			healHp /= 2;
		}
		if (this instanceof L1PetInstance) {
			((L1PetInstance) this).setCurrentHp(this.getCurrentHp() + healHp);
		} else if (this instanceof L1SummonInstance) {
			((L1SummonInstance) this).setCurrentHp(this.getCurrentHp() + healHp);
		} else {
			this.setCurrentHpDirect(this.getCurrentHp() + healHp);
		}
	}

	public void useItem(final int type, final int chance) { // 使用する種類 使用する可能性(％)
		if (this.hasSkillEffect(71)) {
			return; // ディケイ ポーション状態かチェック
		}

		if (Random.nextInt(100) > chance) {
			return; // 使用する可能性
		}

		if (type == USEITEM_HEAL) { // 回復系ポーション
			// 回復量の大きい順
			if (this.getInventory().consumeItem(POTION_OF_GREATER_HEALING, 1)) {
				this.useHealPotion(75, 197);
			} else if (this.getInventory().consumeItem(POTION_OF_EXTRA_HEALING, 1)) {
				this.useHealPotion(45, 194);
			} else if (this.getInventory().consumeItem(POTION_OF_HEALING, 1)) {
				this.useHealPotion(15, 189);
			}
		} else if (type == USEITEM_HASTE) { // ヘイスト系ポーション
			if (this.hasSkillEffect(1001)) {
				return; // ヘイスト状態チェック
			}

			// 効果の長い順
			if (this.getInventory().consumeItem(B_POTION_OF_GREATER_HASTE_SELF, 1)) {
				this.useHastePotion(2100);
			} else if (this.getInventory().consumeItem(POTION_OF_GREATER_HASTE_SELF,
					1)) {
				this.useHastePotion(1800);
			} else if (this.getInventory().consumeItem(B_POTION_OF_HASTE_SELF, 1)) {
				this.useHastePotion(350);
			} else if (this.getInventory().consumeItem(POTION_OF_HASTE_SELF, 1)) {
				this.useHastePotion(300);
			}
		}
	}
}

